home *** CD-ROM | disk | FTP | other *** search
/ Alles Voor Internet / Tout Pour Internet / alles voor internet.iso / MacInternet™ / Telnet / Terminal 2.2 / Project / Sources / Port.c < prev    next >
Text File  |  1992-01-17  |  14KB  |  576 lines

  1. /*
  2.     Terminal 2.2
  3.     "Serial.c"
  4. */
  5.  
  6. #ifdef THINK_C
  7. #include "MacHeaders"
  8. #define CREFNUM(x)    x.ioCRefNum
  9. #endif
  10. #ifdef applec
  11. #pragma load ":(Objects):MacHeadersMPW"
  12. #pragma segment Main2
  13. #define CREFNUM(x)    x.ioCRefNum
  14. #endif
  15.  
  16. #include "Port.h"
  17. #include "Text.h"
  18. #include "Main.h"
  19.  
  20. #ifdef USECTB                    /* Communication Tool Box includes */
  21. #include <CommResources.h>
  22. #include <CRMSerialDevices.h>
  23. #endif
  24.  
  25. #define INPUTLENGTH Config.input        /* Size of input buffer */
  26. #define CURRENTPORT    Settings.portName    /* Current port's name */
  27.  
  28. typedef    struct {
  29.         Byte *name;                /* Port's name */
  30.         Byte *input;            /* Input driver's name */
  31.         Byte *output;            /* Output driver's name */
  32. } SERIALNAME;
  33.  
  34. /* ----- Static data --------------------------------------------------- */
  35.  
  36. static short INPUT = 0;            /* Current input reference number */
  37. static short OUTPUT = 0;        /* Current output reference number */
  38. static short PORTNO = 0;        /* 1 = Modem Port, 2 = Printer Port */
  39. static Ptr inputBuffer = 0;        /* Current input buffer */
  40. static Ptr outputBuffer = 0;    /* Current output buffer */
  41.  
  42. #define baud38400    1            /* Not definded in SerialDvr.h */
  43.  
  44. static short Baud[] = {            /* Baud rates we support */
  45.     baud300,                    /* 0 */
  46.     baud600,                    /* 1 */
  47.     baud1200,                    /* 2 */
  48.     baud2400,                    /* 3 */
  49.     baud4800,                    /* 4 */
  50.     baud9600,                    /* 5 */
  51.     baud19200,                    /* 6 */
  52.     baud38400,                    /* 7 */
  53.     baud57600                    /* 8 */
  54. };
  55. static short Data[] = {            /* Data bits we support */
  56.     data7,                        /* 0 */
  57.     data8                        /* 1 */
  58. };
  59. static short Parity[] = {        /* Parity options we support */
  60.     noParity,                    /* 0 */
  61.     evenParity,                    /* 1 */
  62.     oddParity                    /* 2 */
  63. };
  64. static short StopBits[] = {        /* Stop bits we support */
  65.     stop10,                        /* 0 */
  66.     stop20                        /* 1 */
  67. };
  68.  
  69. static SERIALNAME Names[] = {    /* Used without Communication Tool Box */
  70.         { (Byte *)"\pModem Port", (Byte *)"\p.AIn", (Byte *)"\p.AOut" },
  71.         { (Byte *)"\pPrinter Port", (Byte *)"\p.BIn", (Byte *)"\p.BOut" }
  72. };
  73.  
  74. /* ----- Find serial devices ------------------------------------------- */
  75.  
  76. void SerialDevice(SDPROC callback)
  77. {
  78.     /*    Loop thru all serial devices and call the "callback" function
  79.         with the following arguments:
  80.             1. Index (one based)
  81.             2. Port's name
  82.             3. Input driver's name
  83.             4. Output driver's name
  84.         The "callback" function should return TRUE to stop the search,
  85.         or FALSE to continue. */
  86.  
  87. #ifdef USECTB
  88.     if (CTB) {            /* Communications Toolbox is available */
  89.         register CRMRec *p;
  90.         register long old;
  91.         register CRMSerialRecord *ser;
  92.         register short index;
  93.         CRMRec r;
  94.  
  95.         memset(&r, 0, sizeof(r));
  96.         r.qType = crmType;
  97.         for (old = 0, index = 1; ; old = p->crmDeviceID, ++index) {
  98.             r.crmDeviceType = crmSerialDevice;
  99.             r.crmDeviceID = old;
  100.             if (!(p = (CRMRec *)CRMSearch((QElemPtr)(p = &r))))
  101.                 break;
  102.             ser = (CRMSerialRecord *)p->crmAttributes;
  103.             if ((* callback)(index, *(ser->name), *(ser->inputDriverName),
  104.                     *(ser->outputDriverName)))
  105.                 break;    /* Stop search */
  106.         }
  107.     } else
  108. #endif
  109.     {                /* Communications Toolbox not available */
  110.         register short index;
  111.         register SERIALNAME *p;
  112.  
  113.         for (index = 0, p = Names;
  114.                 index < sizeof(Names)/sizeof(SERIALNAME);
  115.                 ++index, ++p)
  116.             if ((* callback)(index + 1, p->name, p->input, p->output))
  117.                 break;    /* Stop search */
  118.     }
  119. }
  120.  
  121. /* ----- Open serial driver -------------------------------------------- */
  122.  
  123. static short OpenErr;        /* Driver open error */
  124. static Byte *OpenName;        /* Port's name to find */
  125.  
  126. static short OpenSerial(    /* "callback" function for "SerialDevice" */
  127.     short index,
  128.     Byte *name,
  129.     Byte *input,
  130.     Byte *output)
  131. {
  132.     if (!EqualString(name, OpenName, FALSE, TRUE))
  133.         return FALSE;        /* Not the name we want, continue */
  134.     if (OpenErr = OpenDriver(input, &INPUT))
  135.         return TRUE;        /* Name ok, but error during open, stop */
  136.     if (OpenErr = OpenDriver(output, &OUTPUT)) {
  137.         CloseDriver(INPUT);    /* Output open error */
  138.         INPUT = OUTPUT = 0;
  139.     } else {
  140.         DTR = TRUE;            /* Input & output open ok, DTR asserted */
  141.         PORTNO = index;
  142.     }
  143.     return TRUE;            /* Stop, port was found */
  144. }
  145.  
  146. static short OpenSerialDriver(
  147.     Byte *port)                /* Port's name (e.g. "\pModem Port") */
  148. {
  149.     OpenName = port;
  150.     OpenErr = 1;            /* If no port with this name is found */
  151.     DTR = FALSE;            /* DTR negated until port is open */
  152.     PORTNO = 0;
  153.     SerialDevice((ProcPtr)OpenSerial);
  154.     return OpenErr;
  155. }
  156.  
  157. /* ----- Calculate serial duration ------------------------------------- */
  158.  
  159. /*    Note: using speed changing modems (while using MNP4 or MNP5) this
  160.     leads to wrong results... */
  161.  
  162. long SerialDuration(
  163.     register short setup,    /* Serial chip setup word */
  164.     register short bytes)    /* Number of bytes in buffer */
  165. {
  166.     register short bits;    /* Bits per bytes */
  167.     register long bps;        /* Bits per second (*100) */
  168.     short baud, data, parity, stop;
  169.     static long b[] = {        /* Baud * 100 */
  170.         30000, 60000, 120000, 240000, 480000,
  171.         960000, 1920000, 3840000, 5760000 };
  172.  
  173.     SerialGetSetup(setup, &baud, &data, &parity, &stop);
  174.     bits =
  175.         1 +                    /* Start bit */
  176.         7 + data +            /* Data bits (7 or 8) */
  177.         (parity ? 1 : 0) +    /* Parity bit (0 or 1) */
  178.         1 + stop;            /* Stop bits (1 or 2) */
  179.     bps = b[baud];
  180.     return ((long)bits * (long)bytes * 6015L) / bps;
  181. }
  182.  
  183. /* ----- Set serial parameters ----------------------------------------- */
  184.  
  185. void SerialReset(
  186.     register short setup)    /* Serial chip setup word */
  187. {
  188.     SerReset(OUTPUT, setup);
  189.     SerReset(INPUT, setup);
  190. }
  191.  
  192. /* ----- Set to 8 data bits and no parity (binary file transfers) ------ */
  193.  
  194. void SerialBinary(
  195.     register short setup)    /* Serial chip setup word */
  196. {
  197.     /* Parity   : bits 13 - 12 (0, 1, 2, 3 for no, odd, no, even) */
  198.     /* Data bits: bits 11 - 10 (0, 1, 2, 3 for 5, 7, 6, 8) */
  199.     /* --00 11-- ---- ---- */
  200.  
  201.     SerialReset((setup & 0xC3FF) | 0x0C00);
  202. }
  203.  
  204. /* ----- See if set to 8 data bits ------------------------------------- */
  205.  
  206. Boolean Serial8Bits(
  207.     register short setup)    /* Serial chip setup word */
  208. {
  209.     /* Parity   : bits 13 - 12 (0, 1, 2, 3 for no, odd, no, even) */
  210.     /* Data bits: bits 11 - 10 (0, 1, 2, 3 for 5, 7, 6, 8) */
  211.     /* --00 11-- ---- ---- */
  212.  
  213.     return (setup & 0x0C00) == 0x0C00;
  214. }
  215.  
  216. /* ----- DTR on exit, drop or no drop ---------------------------------- */
  217.  
  218. void SerialDropDTR(register Boolean nodrop)
  219. {
  220.     CntrlParam c;
  221.  
  222.     if (!OUTPUT)
  223.         return;
  224.     CREFNUM(c) = OUTPUT;
  225.     c.csParam[0] = nodrop ? 0x8000 : 0x0000;
  226.     c.csCode = 16;
  227.     PBControl((ParmBlkPtr)&c, FALSE);
  228. }
  229.  
  230. /* ----- Set serial handshake ------------------------------------------ */
  231.  
  232. void SerialHandshake(
  233.     register short how)        /* 0=none,1=XON/XOFF,2=CTS,3=DTR,4=CTS/DTR */
  234. {
  235.     CntrlParam c;
  236.     register SerShk *handshake;
  237.  
  238.     if (!OUTPUT)
  239.         return;
  240.     CREFNUM(c) = OUTPUT;
  241.     c.csCode = 14;                /* SerHShake */
  242.     handshake = (SerShk *)&c.csParam[0];
  243.     handshake->fXOn = 0;        /* no XON/XOFF output flow control */
  244.     handshake->fCTS = 0;        /* no CTS (input) hardware handshake */
  245.     handshake->xOn  = 0x00;        /* XON character */
  246.     handshake->xOff = 0x00;        /* XOFF character */
  247.     handshake->errs = 0;        /* Ignore input errors */
  248.     handshake->evts = 0;        /* No device driver events */
  249.     handshake->fInX = 0;        /* no XON/XOFF input flow control */
  250.     handshake->fDTR = 0;        /* no DTR (output) hardware handshake */
  251.     switch(how) {
  252.         case 1:        /* XON/XOFF */
  253.             handshake->fXOn = 1;    /* XON/XOFF output flow control */
  254.             handshake->xOn  = 0x11;    /* XON character (ctrl-Q) */
  255.             handshake->xOff = 0x13;    /* XOFF character (ctrl-S) */
  256.             break;
  257.         case 2:        /* CTS */
  258.             handshake->fCTS = 1;    /* CTS (input) hardware handshake */
  259.             break;
  260.         case 3:        /* DTR */
  261.             handshake->fDTR = 1;    /* DTR (output) hardware handshake */
  262.             break;
  263.         case 4:        /* CTS/DTR */
  264.             handshake->fCTS = handshake->fDTR = 1;
  265.             break;
  266.     }
  267.     PBControl((ParmBlkPtr)&c, FALSE);
  268. }
  269.  
  270. /* ----- Get serial port setup ----------------------------------------- */
  271.  
  272. short SerialGetSetup(
  273.     register short setup,    /* Serial chip setup word */
  274.     short *baud,            /* 0=300 Baud ... */
  275.     short *data,            /* 0=7 bits ... */
  276.     short *parity,            /* 0=none ... */
  277.     short *stop)            /* 0=1 stop bits ... */
  278. {
  279.     register short i;
  280.     register short v;
  281.  
  282.     *baud = *data = *parity = *stop = 0;
  283.  
  284.     v = setup & 0x03FF;                    /* Baud rate: bits 9 - 0 */
  285.     for (i = 0; i < sizeof(Baud)/sizeof(short); i++)
  286.         if (v == Baud[i]) {
  287.             *baud = i;
  288.             break;
  289.         }
  290.     if (i >= sizeof(Baud)/sizeof(short))
  291.         return 1;
  292.  
  293.     v = setup & 0x0C00;                    /* Data bits: bits 11 - 10 */
  294.     for (i = 0; i < sizeof(Data)/sizeof(short); i++)
  295.         if (v == Data[i]) {
  296.             *data = i;
  297.             break;
  298.         }
  299.     if (i >= sizeof(Data)/sizeof(short))
  300.         return 2;
  301.  
  302.     v = setup & 0x3000;                    /* Parity: bits 13 - 12 */
  303.     for (i = 0; i < sizeof(Parity)/sizeof(short); i++)
  304.         if (v == Parity[i]) {
  305.             *parity = i;
  306.             break;
  307.         }
  308.     if (i >= sizeof(Parity)/sizeof(short))
  309.         return 3;
  310.  
  311.     v = setup & 0xC000;                    /* Stop bits: bits 15 - 14 */
  312.     for (i = 0; i < sizeof(StopBits)/sizeof(short); i++)
  313.         if (v == StopBits[i]) {
  314.             *stop = i;
  315.             break;
  316.         }
  317.     if (i >= sizeof(StopBits)/sizeof(short))
  318.         return 4;
  319.  
  320.     return 0;
  321. }
  322.  
  323. /* ----- Set serial port setup ----------------------------------------- */
  324.  
  325. short SerialSetSetup(
  326.     register short baud,    /* 0=300 Baud ... */
  327.     register short data,    /* 0=7 bits ... */
  328.     register short parity,    /* 0=none ... */
  329.     register short stop,    /* 0=1 stop bits ... */
  330.     register short *setup)    /* Serial chip setup word */
  331. {
  332.     *setup = Baud[0] | Data[0] | Parity[0] | StopBits[0];
  333.     if (baud < 0 || baud >= sizeof(Baud)/sizeof(short))
  334.         return 1;
  335.     if (data < 0 || data >= sizeof(Data)/sizeof(short))
  336.         return 2;
  337.     if (parity < 0 || parity >= sizeof(Parity)/sizeof(short))
  338.         return 3;
  339.     if (stop < 0 || stop >= sizeof(StopBits)/sizeof(short))
  340.         return 4;
  341.     *setup = Baud[baud] | Data[data] | Parity[parity] | StopBits[stop];
  342.     return 0;
  343. }
  344.  
  345. /* ----- Close serial port --------------------------------------------- */
  346.  
  347. void SerialClose(void)
  348. {
  349.     /*    Warning! VERY BAD THINGS CAN HAPPEN (Perhaps even loss of data
  350.         on your hard disk!) long after your program quits if you forget
  351.         to do this, or forget to close the driver properly!
  352.         It is essential that you do not ever leave a custom input buffer
  353.         dangling, EVEN if you abort your program for some other reason!
  354.         The OS will NOT fix this up for you! You have been warned! */
  355.  
  356.     if (INPUT) {
  357.         SerSetBuf(INPUT, inputBuffer, 0);
  358.         CloseDriver(INPUT);
  359.         INPUT = 0;
  360.     }
  361.     if (OUTPUT) {
  362.         SerSetBuf(OUTPUT, outputBuffer, 0);
  363.         CloseDriver(OUTPUT);
  364.         OUTPUT = 0;
  365.     }
  366. }
  367.  
  368. /* ----- Open serial port and set parameters --------------------------- */
  369.  
  370. short SerialOpen(
  371.     register Byte *port,        /* Port's name (e.g. "\pModem Port") */
  372.     register short setup,        /* Serial chip setup word */
  373.     register short handshake)    /* 0=none ... */
  374. {
  375.     register short err;
  376.  
  377.     memcpy(CURRENTPORT, port, *port + 1);
  378.     if (port[0] == 0)            /* It's ok to use the "none" port */
  379.         return 0;
  380.     if (err = OpenSerialDriver(port))
  381.         return err;
  382.     /* Keep input buffer if already allocated */
  383.     if (!inputBuffer && !(inputBuffer = NewPtr(INPUTLENGTH))) {
  384.         SerialClose();
  385.         return memFullErr;
  386.     }
  387.     SerSetBuf(INPUT, inputBuffer, INPUTLENGTH);
  388.     SerialHandshake(handshake);
  389.     SerialReset(setup);
  390.     return 0;                    /* Ok */
  391. }
  392.  
  393. /* ----- Read characters from serial port ------------------------------ */
  394.  
  395. void SerialFastRead(
  396.     register Byte *buffer,
  397.     register long count)
  398. {
  399.     IOParam b;
  400.  
  401.     if (!INPUT)
  402.         return;
  403.     b.ioRefNum = INPUT;
  404.     b.ioBuffer = (Ptr)buffer;
  405.     b.ioReqCount = count;
  406.     PBRead((ParmBlkPtr)&b, FALSE);
  407. }
  408.  
  409. /* ----- Read characters from serial port ------------------------------ */
  410.  
  411. long SerialRead(
  412.     register Byte *buffer,
  413.     register long max)
  414. {
  415.     register long n;
  416.     CntrlParam c;
  417.     IOParam b;
  418.  
  419.     if (!INPUT)
  420.         return 0;
  421.     CREFNUM(c) = INPUT;
  422.     c.csCode = 2;
  423.     if (PBStatus((ParmBlkPtr)&c, FALSE))
  424.         return 0;
  425.     if (n = *(long *)&c.csParam[0]) {
  426.         b.ioRefNum = INPUT;
  427.         b.ioBuffer = (Ptr)buffer;
  428.         b.ioReqCount = (max > n) ? n : max;
  429.         return PBRead((ParmBlkPtr)&b, FALSE) ? 0 : b.ioReqCount;
  430.     }
  431.     return 0;    /* Nothing available */
  432. }
  433.  
  434. /* ----- Flush serial input buffer ------------------------------------- */
  435.  
  436. void SerialFlush(void)
  437. {
  438.     CntrlParam b;
  439.  
  440.     if (!INPUT)
  441.         return;
  442.     CREFNUM(b) = INPUT;
  443.     b.ioCompletion = 0;
  444.     PBKillIO((ParmBlkPtr)&b, FALSE);
  445. }
  446.  
  447. /* ----- Abort serial send --------------------------------------------- */
  448.  
  449. void SerialAbort(void)
  450. {
  451.     CntrlParam b;
  452.  
  453.     if (!OUTPUT)
  454.         return;
  455.     CREFNUM(b) = OUTPUT;
  456.     b.ioCompletion = 0;
  457.     PBKillIO((ParmBlkPtr)&b, FALSE);
  458. }
  459.  
  460. /* ----- Send buffer --------------------------------------------------- */
  461.  
  462. static pascal void SendComplete(void);
  463.  
  464. #ifdef THINK_C
  465. static pascal void SendComplete()
  466. {
  467.     /* A0 has address of IOParam */
  468.     asm {
  469.         MOVE.L    -4(A0),A0    /* Get busy flag address */
  470.         CLR.B    0(A0)        /* Clear the busy flag (FALSE) */
  471.     }
  472. }
  473. #endif
  474.  
  475. void SerialSend(
  476.     register Byte *buffer,
  477.     register long count,
  478.     register Boolean *busy)
  479. {
  480.     static struct {        /* Must be static! */
  481.         Boolean *busy;    /* TRUE while sending */
  482.         IOParam b;
  483.     } param;
  484.  
  485.     if (!OUTPUT) {
  486.         *busy = FALSE;
  487.         return;
  488.     }
  489.     *busy = TRUE;
  490.     param.busy = busy;
  491.     param.b.ioCompletion = (ProcPtr)SendComplete;
  492.     param.b.ioRefNum = OUTPUT;
  493.     param.b.ioBuffer = (Ptr)buffer;
  494.     param.b.ioReqCount = count;
  495.     PBWrite((ParmBlkPtr)¶m.b, TRUE);        /* Asynchrone */
  496. }
  497.  
  498. /* ----- See how many bytes are in input buffer ------------------------ */
  499.  
  500. long SerialCheck(void)
  501. {
  502.     CntrlParam c;
  503.  
  504.     if (!INPUT)
  505.         return 0;
  506.     CREFNUM(c) = INPUT;
  507.     c.csCode = 2;
  508.     if (!PBStatus((ParmBlkPtr)&c, FALSE))
  509.         return *(long *)&c.csParam[0];
  510.     return 0;
  511. }
  512.  
  513. /* ----- Negate or assert DTR ------------------------------------------ */
  514.  
  515. void SerialDTR(
  516.     register Boolean how)    /* FALSE: negate, TRUE:assert */
  517. {
  518.     CntrlParam c;
  519.  
  520.     if (!OUTPUT)
  521.         return;
  522.     CREFNUM(c) = OUTPUT;
  523.     c.csCode = how ? 17 : 18;
  524.     PBControl((ParmBlkPtr)&c, FALSE);
  525.     DTR = how;
  526. }
  527.  
  528. /* ----- Check CTS/DCD ------------------------------------------------- */
  529.  
  530. /*
  531.     Pin number    Signal name        Signal description
  532.  
  533.         1            HSKo        Output Handshake (SCC DTR output)
  534.         2            HSKi        Input Handshake (SCC CTS input)
  535.         7            GPi            General-purpose input (SCC DCD input)
  536. */
  537.  
  538. #ifdef QUICK_AND_DIRTY
  539.  
  540. Boolean SerialCTS(void)
  541. {
  542.     register Byte r;
  543.  
  544.     if (!INPUT || PORTNO < 1 || PORTNO > 2)
  545.         return FALSE;
  546.     r = *(SCCRd + ((PORTNO == 2) ? 0 : 2));    /* SCC channel A/B control */
  547.     return !(r & 0x20);                        /* CTS is bit 5 */
  548. }
  549.  
  550. #else
  551.  
  552. Boolean SerialCTS(void)
  553. {
  554.     CntrlParam c;
  555.  
  556.     if (!INPUT)
  557.         return 0;
  558.     CREFNUM(c) = INPUT;
  559.     c.csCode = 8;
  560.     if (!PBStatus((ParmBlkPtr)&c, FALSE))
  561.         return !((SerStaRec *)&c.csParam[0])->ctsHold;
  562.     return 0;
  563. }
  564.  
  565. #endif
  566.  
  567. Boolean SerialDCD(void)
  568. {
  569.     register Byte r;
  570.  
  571.     if (!INPUT || PORTNO < 1 || PORTNO > 2)
  572.         return FALSE;
  573.     r = *(SCCRd + ((PORTNO == 2) ? 0 : 2));    /* SCC channel A/B control */
  574.     return !(r & 0x08);                        /* DCD is bit 3 */
  575. }
  576.